﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Net;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using Newtonsoft.Json;

namespace LuceneApiServerLib
{
    public static class SerializerHelper
    {
        #region Json和对象转换

        /// <summary>
        ///     将对象转换为json格式
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public static string ToJson(this object o)
        {
            return JsonConvert.SerializeObject(o);
        }

        /// <summary>
        ///     json字符串转为对象
        /// </summary>
        /// <typeparam name="T">要转换的类型</typeparam>
        /// <param name="o">json字符串</param>
        /// <returns></returns>
        public static T FromJson<T>(this string o)
        {
            return JsonConvert.DeserializeObject<T>(o);
        }


        /// <summary>
        ///     json字符串转为Object对象
        /// </summary>
        /// <param name="o">json字符串</param>
        /// <returns></returns>
        public static object FromJson(this string o)
        {
            return JsonConvert.DeserializeObject(o);
        }

        /// <summary>
        ///     对象转换为json字符串
        /// </summary>
        /// <typeparam name="T">对象类型</typeparam>
        /// <param name="o">要转换的对象</param>
        /// <returns></returns>
        public static string ToJson<T>(this T o)
        {
            // JsonSerializerSettings set = new JsonSerializerSettings();
            //set.DefaultValueHandling = DefaultValueHandling.Ignore;
            return JsonConvert.SerializeObject(o);
        }

        /// <summary>
        ///     判断对象是否为null,集合对象（包括数组）是否元素个数为0
        /// </summary>
        /// <typeparam name="T">任意对象数据类型</typeparam>
        /// <param name="data">要判断的数据</param>
        /// <returns></returns>
        public static bool IsNullOrEmpty<T>(this T data) where T : class
        {
            if (data == null)
            {
                return true;
            }

            if (data is string)
            {
                return string.IsNullOrEmpty(data as string);
            }

            if (data is ICollection)
            {
                return (data as ICollection).Count == 0;
            }

            return false;
        }

        #endregion

        #region 字符串转换为值类型

        /// <summary>
        ///     将From或则QueryString传过来的值转换为指定类型的值
        /// </summary>
        /// <typeparam name="T">目标数据类型</typeparam>
        /// <param name="dataBag">值来源</param>
        /// <param name="key">值的键</param>
        /// <returns></returns>
        public static T TryGet<T>(this NameValueCollection dataBag, string key)
        {
            return dataBag.TryGet(key, default(T));
        }

        /// <summary>
        ///     将From或则QueryString传过来的值转换为指定类型的值
        /// </summary>
        /// <typeparam name="T">目标数据类型</typeparam>
        /// <param name="dataBag">值来源</param>
        /// <param name="key">值的键</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns></returns>
        public static T TryGet<T>(this NameValueCollection dataBag, string key, T defaultValue)
        {
            if (dataBag.IsNullOrEmpty() || dataBag[key].IsNullOrEmpty())
            {
                return defaultValue;
            }

            return dataBag[key].ParseTo(defaultValue);
        }

        /// <summary>
        ///     将字符串值转换为指定值
        /// </summary>
        /// <typeparam name="T">目标数据类型</typeparam>
        /// <param name="value">要转换的值</param>
        /// <returns></returns>
        public static T ParseTo<T>(this string value)
        {
            return value.ParseTo(default(T));
        }

        /// <summary>
        ///     将字符串值转换为指定值
        /// </summary>
        /// <typeparam name="T">目标数据类型</typeparam>
        /// <param name="value">要转换的值</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns></returns>
        public static T ParseTo<T>(this string value, T defaultValue)
        {
            if (Parser<T>.ParseMethod != null)
                try
                {
                    return Parser<T>.ParseMethod(value);
                }
                catch
                {
                    //do nothing 
                }

            return defaultValue;
        }

        /// <summary>
        ///     将一个类型的数据转换为其他类型的数据
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="value">要转换的数据</param>
        /// <returns></returns>
        public static T ParseTo<T>(this object value)
        {
            return value.ParseTo(default(T));
        }

        /// <summary>
        ///     将一个类型的数据转换为其他类型的数据
        /// </summary>
        /// <typeparam name="T">目标类型</typeparam>
        /// <param name="value">要转换的数据</param>
        /// <param name="defaultValue">默认值</param>
        /// <returns></returns>
        public static T ParseTo<T>(this object value, T defaultValue)
        {
            try
            {
                var convertValue = Convert.ChangeType(value, typeof (T));
                return convertValue.IsNullOrEmpty() ? defaultValue : (T) convertValue;
            }
            catch
            {
                // do nothing
            }
            return defaultValue;
        }

        static SerializerHelper()
        {
            Parser<short>.ParseMethod = short.Parse;
            Parser<int>.ParseMethod = int.Parse;
            Parser<long>.ParseMethod = long.Parse;
            Parser<byte>.ParseMethod = byte.Parse;
            Parser<ushort>.ParseMethod = ushort.Parse;
            Parser<uint>.ParseMethod = uint.Parse;
            Parser<ulong>.ParseMethod = ulong.Parse;
            Parser<sbyte>.ParseMethod = sbyte.Parse;
            Parser<float>.ParseMethod = float.Parse;
            Parser<double>.ParseMethod = double.Parse;
            Parser<decimal>.ParseMethod = decimal.Parse;
            Parser<bool>.ParseMethod = bool.Parse;
            Parser<DateTime>.ParseMethod = DateTime.Parse;
            Parser<TimeSpan>.ParseMethod = TimeSpan.Parse;
            //    Parser<Guid>.ParseMethod = Guid.Parse;
        }

        private class Parser<T>
        {
            public delegate T ParseMethodDelegate(string value);

            private static bool noParseMethod;
            private static ParseMethodDelegate _parseMethod;

            public static ParseMethodDelegate ParseMethod
            {
                get
                {
                    if (_parseMethod != null)
                        return _parseMethod;

                    if (noParseMethod)
                        return null;

                    var method = typeof (T).GetMethod("Parse", new[] {typeof (string)});
                    if (method != null && (method.Attributes & MethodAttributes.Static) != 0)
                    {
                        var dynamicMethod = new DynamicMethod(typeof (T).FullName + "_Parse", typeof (T),
                            new[] {typeof (string)});

                        var il = dynamicMethod.GetILGenerator();
                        il.Emit(OpCodes.Ldarg_0);
                        il.EmitCall(OpCodes.Call, method, null);
                        il.Emit(OpCodes.Ret);

                        return
                            _parseMethod =
                                (ParseMethodDelegate) dynamicMethod.CreateDelegate(typeof (ParseMethodDelegate));
                    }

                    noParseMethod = true;
                    return null;
                }
                set { _parseMethod = value; }
            }
        }

        #endregion
    }

    /// <summary>
    ///     CommonJsonSend中的http提交类型
    /// </summary>
    public enum CommonJsonSendType
    {
        GET,
        POST
    }

    public class GetWebUtil
    {
        #region MyRegion

        public static T GetJson<T>(string url, Dictionary<string, string> paramDictionary)
        {
            var returnText = new WebUtils().DoGet(url, paramDictionary);
            var result = returnText.FromJson<T>();
            return result;
        }

        public static T PostGetJson<T>(string url, IDictionary<string, string> parameters)
        {
            var returnText = new WebUtils().DoPost(url, parameters);
            var result = returnText.FromJson<T>();
            return result;
        }

        public static T PostGetJson<T>(string url, IDictionary<string, string> getparams, object postparams)
        {
            var utils = new WebUtils();
            if (getparams != null && getparams.Count > 0)
            {
                if (url.Contains("?"))
                {
                    url = url + "&" + utils.BuildQuery(getparams);
                }
                else
                {
                    url = url + "?" + utils.BuildQuery(getparams);
                }
            }
            var req = utils.GetWebRequest(url, "POST");
            req.ContentType = "application/json;charset=utf-8";
            var postData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(postparams));
            var reqStream = req.GetRequestStream();
            reqStream.Write(postData, 0, postData.Length);
            reqStream.Close();
            var rsp = (HttpWebResponse) req.GetResponse();
            var encoding = Encoding.GetEncoding(rsp.CharacterSet);
            var re = utils.GetResponseAsString(rsp, encoding);
            var result = re.FromJson<T>();
            return result;
        }

        #endregion
    }
}